#!coding:utf-8
# vim: tabstop=4 shiftwidth=4 softtabstop=4
import Image
import tempfile
import uuid,time
from datetime import datetime

from django.db import transaction
from rest_framework.response import Response
from rest_framework import status
from cvirt.cnode.vm import vm_utils

from cvirt.manager.models import Instance, Server, Network, Storage, Interface, VDisk, FixedIp, Template, Snapshot, SecurityGroup, Proposal, BackupPolicy, User
from cvirt.tasks import create_vm, start_vm, shutdown_vm, reboot_vm, snapshot_vm, delete_vm, pause_vm, unpause_vm, \
    save_as_template, hibernate_vm, snapshot_restore, delete_disk, update_disk, update_cdrom, add_disk, update_vm \
    , snapshot_delete, migrate, pre_migrate,clone_vm
from cvirt.manager.serializers import VMSerializer, InterfaceSerializer, SnapshotSerializer, vdiskSerializer
from cvirt.manager.views import BaseListAPIView, BaseRetriveAPIView, NamedAPIViewMixIn
from cvirt.common import utils, exception
from cvirt.cnode.vm import power_state
from cvirt.cnode.connection import get_connection
from cvirt.common import config,translate as _
from django.http import HttpResponse
from cvirt.manager.models import IscsiLun

conf = config.load_settings()


class VMsLIst(NamedAPIViewMixIn, BaseListAPIView):
    model = Instance
    serializer_class = VMSerializer

    def _get(self, request, *args, **kwargs):
        nouser = self.get_query_string('nouser')
        if nouser:
            qset = Instance.objects.filter(user__isnull=True)
        else:
            qset = Instance.objects.all()
        data = self.paginate(request,qset,VMSerializer)
        return Response(data)

    def get_queryset(self):
        return Instance.objects.order_by('-id')

    def delete(self, request, *args, **kwargs):
        ids = self.get_params('ids')
        return self._do_vm_action(ids, delete_vm)

    def authcheck(self,request,*args,**kwargs):
        if conf.get_bool('license.check'):
            licenseinfo = utils.get_license_info()
            insts = Instance.objects.count()
            available = licenseinfo["inst"] - insts
            if available <= 0:
                return Response(_("虚拟机数量已满，请更新序列号"),status.HTTP_400_BAD_REQUEST)
        return Response(status.HTTP_200_OK)

    @transaction.commit_on_success
    def create(self, request, *args, **kwargs):
        if conf.get_bool('license.check'):
            licenseinfo = utils.get_license_info()
            insts = Instance.objects.count()
            available = licenseinfo["inst"] - insts
            if available <= 0:
                return Response(_("虚拟机数量已满，请更新序列号"),status.HTTP_400_BAD_REQUEST)

        template = self.get_params('template')
        inst = self.get_params('inst')
        desc = inst['desc']
        clusterid = inst['cluster']['id']

        if inst['host']:
            hostid = inst['host']['id']
            host = Server.objects.get_or_none(pk=hostid)
        else:
            #自动选择
            host = self.auto_select_host(Server.objects.filter(cluster_id=clusterid))

        if host is None:
            return Response(_("集群中没有活动的主机"), status.HTTP_400_BAD_REQUEST)

        network = Network.objects.get_or_none(pk=inst['network']['id'])
        storage = Storage.objects.get_or_none(pk=inst['storage']['id'])
        fixip = FixedIp.objects.get_or_none(pk=inst['fixedip']['id'])
        # disk_format = 'qcow2'

        #需要定时任务的支持，根据定时任务的存储使用情况的更新
        if storage.free() - int(inst['disk']) < conf.get_int('disk.reserve') and storage.protocol!='iscsi':
            return Response(_("存储剩余空间%sGB(保留空间%sGB)不足以创建大小为%sGB的磁盘" % (storage.free(),conf.get_int('disk.reserve'), inst['disk'])),
                            status.HTTP_400_BAD_REQUEST)

        #内存不能大于主机内存
        #TODO 是否要根据剩余内存判断
        if host.mem < int(inst['mem']):
            return Response(_('主机剩余内存不足以创建大小为%sMB的虚拟机' % inst['mem']), status.HTTP_400_BAD_REQUEST)

        user = None
        if inst['user']:
            user = User.objects.get_or_none(pk=inst['user']['id'])


        #uuid.uuid4生成uuid对象，数据库存储的是uuid对象？？？
        instance = Instance.objects.create(name=inst['name'], uuid=str(uuid.uuid4()), host=host, status='pending',
                                           power_status=1, graphics_type=inst['graphics_type'], memory=inst['mem'],
                                           vcpu=inst['cpu'], description=desc,remote_password=uuid.uuid4().hex[0:8],
                                           acpi=conf.get_bool('acpi.default'),user=user) #默认开启acpi

        #create 4 interface
        for i in range(4):
            interface = Interface.objects.create(name='eth%s' % i, mac=utils.generate_mac(), model="e1000",
                                                 instance=instance)
            if i == 0:  #默认允许第一个
                #用户选择自动分配，获取fixedip为none，none则表示自动分配
                fixip = fixip if fixip else None
                interface.update(dict(enable=True, network=network, fixedip=fixip))

        image = None
        if template == 'iso':
            exclude, dev = utils.pick_dev([]) #从IDE允许的dev中挑选一个，创建操作不包含已经存在的
            if dev is None:
                return Response(_('虚拟机最多关联4块磁盘,包括cdrom'), status.HTTP_400_BAD_REQUEST)

            #因为isopath可以为空，这里我们检查一下
            isopath = inst['source']['path'] if inst['source'] else None
            cdrom = VDisk.objects.create(name='cdrom', format='qcow2', device_type='cdrom', mountpoint='vda',
                                         isopath=isopath, instance=instance)
            #os_type允许为空
            if inst['os_type']:
                instance.update(dict(os_type=inst['os_type']['name']))
        else:
            #因为image可以为空，这里我们检查一下
            imageid = inst['source']['id'] if inst['source'] else None
            image = Template.objects.get_or_none(pk=imageid)
            if image:
                instance.update(dict(os_type=image.os_type))

        if storage.protocol == 'iscsi':
            lun = inst['lun']
            #TODO:for transaction, here need to raise exception?
            if str(lun['type']) != 'lun':
                VDisk.objects.filter(id=lun['id']).update(instance=instance,mountpoint='vdb')
            else:
                disk_size = float(lun['size'])
                vdisk = VDisk.objects.create(name=lun['lunid'], format='raw', device_type='disk',
                                             size=disk_size, max_size=disk_size, mountpoint='vdb',
                                             storage=storage, bus='ide', instance=instance,image=image)
                IscsiLun.objects.create(target=storage.target, path=lun['path'], vdisk=vdisk, lun=lun['lunid'])
        else:
            vdisk = VDisk.objects.create(name='disk1', format='qcow2', device_type='disk',
                                     size=inst['disk'], max_size=inst['disk'], mountpoint='vdb',
                                     storage=storage, instance=instance, image=image, bus='ide')#bus默认是ide

        if inst['saveproposal']:
            Proposal.objects.create(name=inst['proposalname'], memory=inst['mem'],
                                    disk=inst['disk'], cpu=inst['cpu'], network=network, storage=storage,
                                    interface_type="e1000")
        result = create_vm.async_call(host.host_name, instance)
        data = self.get_serializer(instance).data
        data.update(dict(activity=result.id))
        return Response(data)

    @transaction.autocommit
    def _do_vm_action(self, ids, task_func, **kwargs):
        '''
        循环异步调用也需要释放事务，否则会导致第二个任务开始被死锁
        @param ids:
        @param task_func:
        @param kwargs:
        @return:
        '''
        if ids:
            for id in ids:
                inst = Instance.objects.get(pk=id)
                task = task_func.async_call(inst.host.host_name, inst, **kwargs)

            return Response(dict(activity=task.id), status=200)
        else:
            return Response("ids can not be null", status=status.HTTP_400_BAD_REQUEST)

    def start(self, request, *args, **kwargs):
        ids = self.get_params('ids')
        return self._do_vm_action(ids, start_vm)

    def soft_shutdown(self, request, *args, **kwargs):
        ids = self.get_params('ids')
        return self._do_vm_action(ids, shutdown_vm, is_soft=True)

    def shutdown(self, request, *args, **kwargs):
        ids = self.get_params('ids')
        return self._do_vm_action(ids, shutdown_vm)

    def soft_reboot(self, request, *args, **kwargs):
        ids = self.get_params('ids')
        return self._do_vm_action(ids, reboot_vm, is_soft=True)

    def reboot(self, request, *args, **kwargs):
        ids = self.get_params('ids')
        return self._do_vm_action(ids, reboot_vm)

    def suspend(self, request, *args, **kwargs):
        ids = self.get_params('ids')
        return self._do_vm_action(ids, pause_vm)

    def unsuspend(self, request, *args, **kwargs):
        ids = self.get_params('ids')
        return self._do_vm_action(ids, unpause_vm)

    def hibernate(self, request, *args, **kwargs):
        ids = self.get_params('ids')
        return self._do_vm_action(ids, hibernate_vm)


    def status(self, request, *args, **kwargs):
        ids = self.get_query_string('ids')
        if ids:
            insts = Instance.objects.filter(id__in=map(int, ids.split(',')))
            for i in insts:
                try:
                    #如果host被关闭了，则不需要检测vm状态了
                    if i.host.status != 2:
                        i.update(dict(status="shutdown"))
                    else:
                        i.update(dict(status=vm_utils.vm_status(i.host.ip, i.name)))
                except Exception as e:
                    i.update(dict(status="shutdown"))

            return Response([{'cpu_usage': inst.cpu_usage,
                              'id': inst.id,
                              'mem_usage': inst.mem_usage,
                              'status': inst.status} for inst in insts])
        return Response({})


class VMInfo(NamedAPIViewMixIn, BaseRetriveAPIView):
    model = Instance
    serializer_class = VMSerializer
    interface_serializer_class = InterfaceSerializer

    def _get(self, request, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        if instance:
            return Response(self.get_serializer(instance).data)
        return Response("vm id can not be null", status.HTTP_400_BAD_REQUEST)

    @transaction.commit_on_success
    def save_as_template(self, request, *args, **kwargs):
        id = self.get_params('id')
        template = self.get_params('template')
        if id and template:
            vdisk = VDisk.objects.first(instance_id=id, device_type='disk')
            if vdisk.instance.status == power_state.name(power_state.RUNNING):
                return Response(_('请确保虚拟机处于关机状态'), status.HTTP_400_BAD_REQUEST)

            if vdisk:
                storage = Storage.objects.get_or_none(pk=template['storage']['id'])
                if storage:
                    #如果是本地存储，记录存储对应的host
                    storagehost = vdisk.instance.host.ip if storage.protocol == 'local' else None
                    image = Template.objects.create(name=template['name'], description=template['desc'],
                                                    format=vdisk.format, size=vdisk.size,
                                                    os_type=template['os_type']['name'],
                                                    storage=storage, status='building', storagehost=storagehost)
                    save_as_template.async_call(vdisk.instance.host.host_name, vdisk, image)
                    return Response(200)

        return Response("instance id and template params can not be null", status.HTTP_400_BAD_REQUEST)

    @transaction.commit_on_success
    def snapshot(self, request, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        snap_name = self.get_params('name')
        snap_desc = self.get_params('desc')
        if instance:
            # if instance.status != 'running':
            #     return Response(_('只能对运行状态的虚拟机进行快照操作'), status.HTTP_400_BAD_REQUEST)
            if Snapshot.objects.first(name=snap_name, instance=instance):
                return Response(_('快照已存在'), status.HTTP_400_BAD_REQUEST)
            snap = Snapshot.objects.create(name=snap_name, description=snap_desc,
                                           instance=instance, uuid=uuid.uuid4().hex,
                                           status=power_state.name(power_state.BUILDING))

            result = snapshot_vm.async_call(instance.host.host_name, instance, snap)
            data = SnapshotSerializer(snap).data
            data.update(dict(activity=result.id))
            return Response(data)
        return Response("instance can not be null", status.HTTP_400_BAD_REQUEST)

    def snapshot_restore(self, request, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        if instance:
            snap = Snapshot.objects.get_or_none(pk=self.get_params('snap_id'))
            if snap:
                result = snapshot_restore.async_call(instance.host.host_name, instance, snap)
                return Response(dict(activity=result.id))
        return Response("instance can not be null", status.HTTP_400_BAD_REQUEST)

    def snapshot_delete(self, request, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        if instance:
            snap = Snapshot.objects.get_or_none(pk=self.get_params('snap_id'))
            if snap:
                result = snapshot_delete.async_call(instance.host.host_name, instance, snap)
                return Response(dict(activity=result.id))
        return Response("instance can not be null", status.HTTP_400_BAD_REQUEST)


    def snapshot_list(self, request, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        qset = Snapshot.objects.filter(instance=instance, status='ok')
        data = self.paginate(request, qset, SnapshotSerializer)
        return Response(data)

    def interfaces(self, request, *args, **kwargs):
        '''
        查找启用的网卡
        @param request:
        @param args:
        @param kwargs:
        @return:
        '''
        instance = Instance.objects.get(pk=self.pk)
        if instance:
            interfaces = Interface.objects.filter(instance=instance, enable=True)
            return Response(self.interface_serializer_class(interfaces).data)
        return Response('vm can not be null', status.HTTP_400_BAD_REQUEST)

    @transaction.commit_on_success
    def update(self, request, *args, **kwargs):
        vm = self.get_params('vm')
        instance = Instance.objects.get_or_none(pk=vm['id'])
        if instance:
            for i in range(1, 5):
                face = vm['interface%s' % i]
                iface = instance.interface_set.first(name='eth%s' % (i - 1))  #从eth0开始
                fixip = iface.fixedip
                if fixip:
                    fixip.update(dict(allocated=False)) #释放之前的fixedip
                if iface:
                    if face['enable']:
                        network_id = face['network']['id'] if face['network'] else None
                        network = Network.objects.get_or_none(pk=network_id)
                        if network:
                            if network.should_allocate_ip():
                                fixip = face['fixedip']['id'] if face['fixedip'] else None
                                fixip = FixedIp.objects.get_or_none(pk=fixip)
                                iface.update(dict(fixedip=fixip))
                            iface.update(dict(network=network, model=face['model'], mac=face['mac'], enable=True))
                        else:
                            return Response('network can not be null', status.HTTP_400_BAD_REQUEST)

                        groups = [SecurityGroup.objects.get_or_none(pk=groupid) for groupid in face['selectedgroup']]
                        iface.update(dict(securitygroups=groups))
                    else:
                        iface.update(dict(enable=False, network=None,fixedip=None))#如果取消网卡则释放fixedip

            soundcard = vm['soundcard'] if vm['soundenable'] else None

            backupid = vm['backup_policy']['id'] if vm['backup_policy'] else None

            backup_policy = BackupPolicy.objects.get_or_none(pk=backupid)

            #os_type可以为空，所有需要检查
            os_type = vm['os_type']['name'] if vm['os_type'] else None

            if vm['user']:
                user = User.objects.get_or_none(pk=vm['user']['id'])
                instance.update(dict(user=user))

            instance.update(
                dict(name=vm['name'],description=vm['description'], memory=vm['memory'], vcpu=vm['vcpu'], os_type=os_type,
                     autostart=vm['autostart'], bootmenu=vm['bootmenu'], bootorder=vm['bootorder'],
                     acpi=vm['acpi'], apic=vm['apic'], clock=vm['clock'], hapriority=vm['hapriority'],
                     resetmode=vm['resetmode'], soundcard=soundcard, backup_policy=backup_policy,
                     image_compress=vm['image_compress'],jpeg_compress=vm['jpeg_compress'],
                     streaming_mode=vm['streaming_mode'],usbredir=vm['usbredir'],monitor=vm['monitor'],
                     vram=vm['vram'],graphics_type=vm['graphics_type'],
                     watchdog=vm['watchdog'],dogaction=vm['dogaction'],cpu_host_model=vm['cpu_host_model'],
                     nestedvt=vm['nestedvt']))

            result = update_vm.async_call(instance.host.host_name, instance)
            data = VMSerializer(instance).data
            data.update(dict(activity=result.id))
            return Response(data)

        return Response('instance id can not be null', status.HTTP_400_BAD_REQUEST)


    def delete_disk(self, request, *args, **kwargs):
        cleanup = self.get_params('cleanup')
        instance = Instance.objects.get_or_none(pk=self.pk)
        disk = VDisk.objects.get_or_none(pk=self.get_params('disk')['id'])
        if instance and disk:
            result = delete_disk.async_call(disk.instance.host.host_name, disk, cleanup=cleanup)
            return Response(dict(activity=result.id))

        return Response('instance and disk id can not be null', status.HTTP_400_BAD_REQUEST)

    @transaction.commit_on_success
    def update_disk(self, request, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        disk = self.get_params('disk')
        vdisk = VDisk.objects.get_or_none(pk=disk['id'])
        if instance and vdisk:
            if vdisk.device_type == 'cdrom':
                vdisk.update(dict(isopath=disk['isopath']))
                result = update_cdrom.async_call(instance.host.host_name, vdisk)
            elif vdisk.device_type == 'disk':
                size = vdisk.size if vdisk.size > disk['size'] else disk['size'] #修改的大小不能小于原来的大小

                #size有变化才检查磁盘空间
                if size != vdisk.size and vdisk.storage.free() - int(size) < conf.get_int('disk.reserve'):
                    return Response(_('存储剩余空间%s不足以创建大小为%s的磁盘' % (vdisk.storage.free(), size)),
                                status.HTTP_400_BAD_REQUEST)

                vdisk.update(dict(size=size,
                                  cache=disk['cache'], iomode=disk['iomode'], bus=disk['bus']))
                result = update_disk.async_call(instance.host.host_name, vdisk)
            return Response(dict(activity=result.id))

        return Response('instance and disk can not be null', status.HTTP_400_BAD_REQUEST)

    @transaction.commit_on_success
    def add_disk(self, request, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        disk = self.get_params('disk')
        if instance and disk:
            #获取已经存在的dev标示
            disk_num = VDisk.objects.values('mountpoint').filter(instance=instance).count()
            if disk_num > 3:
                return Response(_('虚拟机最多关联4块磁盘,包括cdrom'), status.HTTP_400_BAD_REQUEST)

            if disk['device_type'] == 'cdrom':
                vdisk = VDisk.objects.create(name='cdrom', format='raw', device_type=disk['device_type'],
                                             isopath=disk['isopath'], instance=instance)
            elif disk['device_type'] == 'disk':
                storage = Storage.objects.get_or_none(pk=disk['storage']['id'])
                if storage:
                    if storage.protocol == 'iscsi':
                        lun = disk['lun']
                        if lun.get('id',None):
                            vdisk = VDisk.objects.first(id=lun['id'])
                            VDisk.objects.filter(id=lun['id']).update(instance=instance)
                        else:
                            # name, device, size, path = lun.split('|')
                            disk_size = int(lun['size'])
                            vdisk = VDisk.objects.create(name=lun['lunid'], format='raw', device_type='disk',
                                                         size=disk_size,
                                                         storage=storage, bus='ide', instance=instance)
                            IscsiLun.objects.create(target=storage.target, path=lun.path, vdisk=vdisk, lun=lun['lunid'])
                    else:
                        vdisk = VDisk.objects.create(name=disk['name'], format=disk['format'],
                                                 device_type=disk['device_type'],
                                                 size=disk['size'],
                                                 storage=storage, instance=instance,bus=disk['bus'])
            if vdisk:
                self.re_order_disk(instance)
                result = add_disk.async_call(instance.host.host_name, vdisk)
                data = vdiskSerializer(vdisk).data
                data.update(dict(activity=result.id))
                return Response(data)

            return Response('invalid parameters', status.HTTP_400_BAD_REQUEST)

        else:
            Response('instance and disk can not be null', status.HTTP_400_BAD_REQUEST)

    @transaction.commit_on_success
    def attach_disk(self, request, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        disk_id = self.get_params('disk')
        vdisk = VDisk.objects.get_or_none(pk=disk_id)
        if instance and vdisk:
            disk_num = VDisk.objects.values('mountpoint').filter(instance=instance).count()
            if disk_num > 3:
                return Response(_('虚拟机最多关联4块磁盘,包括cdrom'), status.HTTP_400_BAD_REQUEST)

            #每次关联到新的vm时，disk dev需要重新设置
            vdisk.update(dict(instance=instance))
            self.re_order_disk(instance)

            result = add_disk.async_call(instance.host.host_name, vdisk)
            data = vdiskSerializer(vdisk).data
            data.update(dict(activity=result.id))
            return Response(data)
        else:
            Response('instance and disk can not be null', status.HTTP_400_BAD_REQUEST)

    def re_order_disk(self,instance):
        devs = {str(0):'vda',str(1):'vdb',str(2):'vdc',str(3):'vdd'}
        for index,vdisk in enumerate(instance.vdisk_set.order_by('updated_at')):
            vdisk.update(dict(mountpoint=devs[str(index)]))

    def current_traffic(self, req, *args, **kwargs):
        stime, result = self._current_usage(req, 'network', *args, **kwargs)
        return Response(dict(line1=[stime, result[0]], line2=[stime, result[1]]))

    def current_disk(self, req, *args, **kwargs):
        stime, result = self._current_usage(req, 'disk', *args, **kwargs)
        return Response(dict(line1=[stime, result[0]], line2=[stime, result[1]]))

    def _current_usage(self, req, type, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        stime = datetime.strftime(datetime.now(), '%H:%M:%S')
        try:
            conn = get_connection(conf['life.migration.uri'] % instance.host.ip)
            result = vm_utils.vminfo(conn, instance, type)
        except Exception as e:
            return stime, 0 if type == 'cpu' else (0, 0)
        return stime, result

    def current_cpu(self, req, *args, **kwargs):
        return Response(dict(line1=self._current_usage(req, 'cpu', *args, **kwargs)))

    @transaction.autocommit
    def migrate(self, req, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        migrateinfo = self.get_params('migrate')
        bandwidth = migrateinfo['bandwidth'] if migrateinfo['bandwidth'] else 0
        if instance:
            if not migrateinfo['host']:
                desthost = self.auto_select_host(Server.objects.filter(cluster_id=instance.host.cluster.id)
                                        .exclude(id=instance.host.id))
                if not desthost:
                    return Response(_("集群中没有活动的主机"),status.HTTP_400_BAD_REQUEST)
            else:
                desthost = Server.objects.get_or_none(host_name=migrateinfo['host']['host_name'])

            try:
                pre_migrate.call(desthost.host_name, instance)
            except exception.InvalidMigrateStorage:
                return Response(_("目标主机[%s]未找到虚拟机磁盘存储，迁移失败!这有可能是使用本地存储导致的."
                                  % desthost.host_name), status.HTTP_400_BAD_REQUEST)
            except exception.InvalidMigrateNetwork:
                return Response(_("目标主机[%s]未找到虚拟机网络，迁移失败" % desthost.host_name), status.HTTP_400_BAD_REQUEST)

            activity = migrate.async_call(instance.host.host_name, instance, desthost,
                                        offline=migrateinfo['offline'], timeout=migrateinfo['timeout'],
                                        bandwidth=bandwidth)
            instance.host = desthost
            result = VMSerializer(instance).data
            result.update(dict(activity=activity.id))
            return Response(result)
        return Response('vm can not be null', status.HTTP_400_BAD_REQUEST)


    @transaction.autocommit
    def screen_shot(self, req, *args, **kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        if instance and instance.status != 'shutdown':
            def handler(stream, buf, fd):
                fd.write(buf)
                fd.flush()

            _,shot_file = tempfile.mkstemp(suffix=instance.name)
            conn = get_connection(conf['life.migration.uri']% instance.host.ip)
            stream = conn.newStream(0)
            try:
                domain = conn.lookupByName(instance.name)
                domain.screenshot(stream, 0, 0)
                stream.recvAll(handler, file(shot_file, 'w'))
                Image.open(file(shot_file)).save('%s.jpg' % shot_file)#默认是pnm格式，需要减少尺寸
                with file('%s.jpg' % shot_file) as f:
                    jpg = f.read()
                response = HttpResponse(jpg)
                response['Content-Type'] = 'image/jpg'
                return response
            except:
                return Response("cannot convert ppn to jpg",status=status.HTTP_400_BAD_REQUEST)
            finally:
                stream.finish()

        return Response(400)

    def clone(self,req,*args,**kwargs):
        instance = Instance.objects.get_or_none(pk=self.pk)
        newvm = self.get_params('newvm')
        desthost = Server.objects.get_or_none(pk=newvm['host']['id'])
        if instance and newvm and desthost:
            if Instance.objects.filter(name=newvm['name']):
                return Response(_('虚拟机%s已经存在' % newvm['name']),status.HTTP_400_BAD_REQUEST)
            instance.id = None
            instance.save()#clone django model

            originvm = Instance.objects.get_or_none(pk=self.pk)
            disk_relattion = {}
            for vdisk in originvm.vdisk_set.all():
                vdiskid = vdisk.id
                originpath = vdisk.disk_path if vdisk.device_type == 'disk' else None
                vdisk.update(dict(id=None,instance = instance)) #clone django model
                if vdisk.device_type == 'disk':
                    newstorage = newvm['storage']["%s%s" % (vdisk.name,vdiskid)]
                    newstorage = Storage.objects.get_or_none(pk=newstorage['id'])
                    vdisk.update(dict(storage=newstorage))
                    disk_relattion[originpath] = vdisk.disk_path
                else:
                    if not newvm['samecdrom']:
                        vdisk.update(dict(isopath = None))


            for iface in originvm.interface_set.all():
                ifaceid = iface.id
                iface.update(dict(id=None,fixedip=None))
                iface.update(dict(instance = instance,mac = utils.generate_mac())) #clone django model
                if iface.enable:
                    newnetwork = newvm['network']["%s%s" % (iface.name,ifaceid)]
                    iface.network_id = newnetwork['id']
                iface.save()

            # if newvm['fullclone']:
            #     for snap in originvm.snapshot_set.all():
            #         snap.update(dict(id=None))
            #         instance.snapshot_set.add(snap)

            instance.name = newvm['name']
            instance.uuid = str(uuid.uuid4())
            instance.save()

            result = clone_vm.async_call(desthost.host_name,disk_relattion,instance,originvm, fullclone=newvm['fullclone'])
            data = self.get_serializer(instance).data
            data.update(dict(activity=result.id))
            return Response(data)
        return Response('vm id or parameter can not be null')




